using Admin2025.Domain.Events;
using MediatR;
using System.Reflection;

namespace Admin2025.Application.Events;

/// <summary>
/// 基于反射的领域事件通知工厂
/// 自动发现并创建对应的通知类型，无需手动维护映射关系
/// </summary>
public class ReflectionDomainEventNotificationFactory : IDomainEventNotificationFactory
{
    private static readonly Dictionary<Type, Type> _eventToNotificationMap = new();
    private static readonly object _lock = new();
    private static bool _initialized = false;

    /// <summary>
    /// 根据领域事件创建对应的MediatR通知
    /// </summary>
    /// <param name="domainEvent">领域事件</param>
    /// <returns>MediatR通知，如果没有对应的通知类型则返回null</returns>
    public INotification? CreateNotification(IDomainEvent domainEvent)
    {
        EnsureInitialized();
        
        var eventType = domainEvent.GetType();
        
        if (_eventToNotificationMap.TryGetValue(eventType, out var notificationType))
        {
            try
            {
                // 创建通知实例，假设构造函数接受领域事件作为参数
                return (INotification?)Activator.CreateInstance(notificationType, domainEvent);
            }
            catch (Exception)
            {
                // 如果创建失败，返回null
                return null;
            }
        }
        
        return null;
    }

    /// <summary>
    /// 初始化事件到通知的映射关系
    /// </summary>
    private static void EnsureInitialized()
    {
        if (_initialized) return;
        
        lock (_lock)
        {
            if (_initialized) return;
            
            BuildEventToNotificationMap();
            _initialized = true;
        }
    }

    /// <summary>
    /// 构建事件到通知的映射关系
    /// 扫描当前程序集中所有实现了INotification的类，
    /// 查找其构造函数参数类型，如果参数类型实现了IDomainEvent，则建立映射关系
    /// </summary>
    private static void BuildEventToNotificationMap()
    {
        var currentAssembly = Assembly.GetExecutingAssembly();
        
        // 找到所有实现INotification的类型
        var notificationTypes = currentAssembly.GetTypes()
            .Where(t => t.IsClass && !t.IsAbstract && typeof(INotification).IsAssignableFrom(t))
            .ToArray();

        foreach (var notificationType in notificationTypes)
        {
            // 查找构造函数，寻找接受IDomainEvent参数的构造函数
            var constructors = notificationType.GetConstructors();
            
            foreach (var constructor in constructors)
            {
                var parameters = constructor.GetParameters();
                
                // 如果构造函数只有一个参数，且该参数实现了IDomainEvent
                if (parameters.Length == 1)
                {
                    var parameterType = parameters[0].ParameterType;
                    if (typeof(IDomainEvent).IsAssignableFrom(parameterType))
                    {
                        _eventToNotificationMap[parameterType] = notificationType;
                        break; // 找到匹配的构造函数就停止
                    }
                }
            }
        }
    }
}
